﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using EuroManager.Domain.Simulator.Engine;
using EuroManager.Domain.Simulator.Helpers;
using EuroManager.Domain.Simulator.World;

namespace EuroManager.Domain.Simulator.AI.States
{
    public class ControlBallState : IState
    {
        private static readonly float maxShootingDistance = 40;

        private IPlayer player;
        private IRandomizer random;

        public ControlBallState(IPlayer player, IRandomizer random)
        {
            Contract.Requires(player != null);
            Contract.Requires(random != null);

            this.player = player;
            this.random = random;
        }

        public void Execute()
        {
            if (player.HasBall)
            {
                if (player.CanReachBall)
                {
                    if (random.ShouldShoot(CalculateShootingChance()))
                    {
                        player.Shoot();
                    }
                    else
                    {
                        var receivers = player.VisiblePlayersFromOwnTeam;

                        if (receivers.Any() && random.ShouldPassBall(0.5f))
                        {
                            PassBall(receivers);
                        }
                        else
                        {
                            player.PushBallForward();
                        }
                    }
                }
                else
                {
                    player.ChaseBall();
                }
            }
            else
            {
                player.Observe();
            }
        }

        private void PassBall(IEnumerable<IPlayer> receivers)
        {
            var chances = receivers.Select(p => 1 / (2 * player.DistanceTo(p) + p.DistanceToOpponentGoal + 0.1f));
            IPlayer receiver = random.PlayerToPassBallTo(receivers, chances.ToArray());
            player.PassBall(receiver);
        }

        private float CalculateShootingChance()
        {
            float chance = 0;

            if (player.IsFacingOpponentGoal)
            {
                float distance = player.DistanceToOpponentGoal;

                if (distance <= maxShootingDistance)
                {
                    chance = Maths.Cos(distance * 0.5f * Maths.Pi / maxShootingDistance);
                }
            }

            return chance;
        }
    }
}
